
//include Qt
#include <iostream>
#include <QApplication>
#include <QFileDialog>
#include <QLineEdit>
#include <QMessageBox>
#include <QLibrary>
#include <QSettings>
#include <QStandardItem>
#include <QPushButton>
#include <QRegExp>
#include <QWidget>
//Include internal
#include "BdPluginManager.h"
#include "BdPluginItem.h"
#include "BdPluginRegistry.h"
#include "BdTraceTerminal.h"
#include "BdPlugin.h"
#include "BdItemDetaillerData.h"


const int PLUGIN_DATA_ROLE=Qt::UserRole;
const int PLUGIN_LIBRARY_ROLE=Qt::UserRole + 1;
const int PLUGIN_LIBRARY_NAME_ROLE=Qt::UserRole + 2;

BdPluginManager::BdPluginManager(QWidget* parent) :
    QDialog(parent)
{
  //UI function
  setupUi(this);
  
  //Initialisation du model
  setTable();
  
  
  //Show the dialog
  show();
  
}

BdPluginManager::~BdPluginManager()
{
  delete mModelPlugins;
}

void BdPluginManager::setTable()
{
  mModelPlugins= new QStandardItemModel(0,1);
  //vwPlugins->setModel(mModelProxy);
  vwPlugins->setFocus();
  vwPlugins->setItemDelegateForColumn(0,new BdItemDetaillerData());
}

void BdPluginManager::accept()
{
  unload();
  done(1);
}

void BdPluginManager::unload()
{
  QSettings settings;
  
  BdTraceTerminal::instance()->information("Check for plugin unload");
  
  for (int row=0;row < mModelPlugins->rowCount();row++)
  {
    // FPV - I want to use index. You can do evrething with item.
    QModelIndex myIndex=mModelPlugins->index(row,0);
    if (mModelPlugins->data(myIndex,Qt::CheckStateRole).toInt() == 0)
    {
      // iThe plugin name without version string in its data PLUGIN_LIB [ts]
      myIndex=mModelPlugins->index(row,0);
      // its off -- see if it is loaded and if so, unload it
      BdPluginRegistry* pRegistry = BdPluginRegistry::instance();
      BdTraceTerminal::instance()->information(QString("Checking to see if ") + mModelPlugins->data(myIndex, PLUGIN_LIBRARY_NAME_ROLE).toString() + QString(" is loaded"));
      
      QString pluginName = mModelPlugins->data(myIndex,PLUGIN_LIBRARY_NAME_ROLE).toString();
      //
      BdPlugin* plugin = pRegistry->plugin(pluginName);
      
      if (plugin)
      {
         plugin->unload();
      }
      //disable it to the qsettings file [ts]
      settings.setValue("/Plugins/" + pluginName, false);
     // remove the plugin from the registry
     pRegistry->removePlugin(pluginName);
    }
  }
}

void BdPluginManager::getPlugins()
{
  QString sharedLibExtension;
#ifdef WIN32
  sharedLibExtension = "*.dll";
#else
  sharedLibExtension = "*.so*";
#endif

// check all libs in the current plugin directory and get name and descriptions
  QDir pluginDir(lblPluginDir->text(), sharedLibExtension, QDir::Name | QDir::IgnoreCase, QDir::Files | QDir::NoSymLinks);

  if (pluginDir.count() == 0)
  {
    QMessageBox::information(this, tr("No Plugins"), tr("No Bd plugins found in ") + lblPluginDir->text());
    return;
  }

  BdTraceTerminal::instance()->information("Bd plugins :");
  for (uint i = 0; i < pluginDir.count(); i++)
  {
    QString lib = QString("%1/%2").arg(lblPluginDir->text()).arg(pluginDir[i]);

#ifdef TESTLIB
          // This doesn't work on WIN32 and causes problems with plugins
          // on OS X (the code doesn't cause a problem but including dlfcn.h
          // renders plugins unloadable)
#if !defined(WIN32) && !defined(Q_OS_MACX)
          // test code to help debug loading problems
          // This doesn't work on WIN32 and causes problems with plugins
          // on OS X (the code doesn't cause a problem but including dlfcn.h
          // renders plugins unloadable)

//          void *handle = dlopen((const char *) lib, RTLD_LAZY);
    void *handle = dlopen(lib.toLocal8Bit().data(), RTLD_LAZY | RTLD_GLOBAL);
    if (!handle)
    {
      BdTraceTerminal::instance()->erreur("In dlopen: ");
      BdTraceTerminal::instance()->erreur(dlerror());
    }
    else
    {
      BdTraceTerminal::instance()->information("dlopen suceeded for " + lib);
      dlclose(handle);
    }
#endif //#ifndef WIN32 && Q_OS_MACX
#endif //#ifdef TESTLIB

    BdTraceTerminal::instance()->information("Examining: " + lib);
    QLibrary *myLib = new QLibrary(lib);
    bool loaded = myLib->load();
    
    if (!loaded)
    {
      BdTraceTerminal::instance()->erreur("Failed to load: " + myLib->fileName());
      delete myLib;
      continue;
    }

    BdTraceTerminal::instance()->information("Loaded library: " + myLib->fileName());
    
    // resolve the metadata from plugin
    name_t *pName = (name_t *) myLib->resolve("name");
    description_t *pDesc = (description_t *) myLib->resolve("description");
    //version_t *pVersion = (version_t *) myLib->resolve("version");

    // show the values (or lack of) for each function
    if(pName)
    {
      BdTraceTerminal::instance()->information("Plugin name: " + pName());
    }
    else
    {
      BdTraceTerminal::instance()->information("Plugin name not returned when queried\n");
    }
    if(pDesc)
    {
      BdTraceTerminal::instance()->information("Plugin description: " + pDesc());
    }
    else
    {
      BdTraceTerminal::instance()->information("Plugin description not returned when queried\n");
    }
//     if(pVersion)
//     {
//       QgsDebugMsg("Plugin version: " + pVersion());
//     }
//     else
//     {
//       QgsDebugMsg("Plugin version not returned when queried\n");
//     }

    if (!pName || !pDesc) //|| !pVersion)
    {
      BdTraceTerminal::instance()->warning("Failed to get name, description, or type for " + myLib->fileName());
      delete myLib;
      continue;
    }

    QString myLibraryName = pluginDir[i];
    // filtering will be done on the display role so give it name and desription
    // user wont see this text since we are using a custome delegate
    QStandardItem * mypDetailItem = new QStandardItem(pName() + " - " + pDesc());
    mypDetailItem->setData(myLibraryName,PLUGIN_LIBRARY_ROLE);
    mypDetailItem->setData(pName(), PLUGIN_LIBRARY_NAME_ROLE); //for matching in registry later
    BdItemDetaillerData myData;
    myData.setTitle(pName());
    myData.setDetail(pDesc());
    myData.setRenderAsWidget(false);
    QVariant myVariant = qVariantFromValue(myData);
    //round trip test - delete this...no need to uncomment
    //QgsDetailedItemData myData2 = qVariantValue<QgsDetailedItemData>(myVariant);
    //Q_ASSERT(myData.title() == myData2.title());
    //round trip test ends
    mypDetailItem->setData(myVariant,PLUGIN_DATA_ROLE);
    // Let the first col  have a checkbox
    mypDetailItem->setCheckable(true);
    mypDetailItem->setEditable(false);

    BdTraceTerminal::instance()->information("Getting an instance of the QgsPluginRegistry");

    // check to see if the plugin is loaded and set the checkbox accordingly
    BdPluginRegistry *pRegistry = BdPluginRegistry::instance();
    QString libName = pRegistry->path(pName());

    // get the library using the plugin description
    if (libName.length() == 0)
    {
      BdTraceTerminal::instance()->warning("Couldn't find library name in the registry");
    }
    else
    {
      BdTraceTerminal::instance()->information("Found library name in the registry");
      if (libName == myLib->fileName())
      {
        // set the checkbox
        mypDetailItem->setCheckState(Qt::Checked);
      }
    }
    // Add items to model
    mModelPlugins->appendRow(mypDetailItem);

    delete myLib;
  }
}
